<template>
  <!-- 
    表单配置项可查看src\views\businessManagement\equipment\deviceInfomation\calibrationRecordList\components\add-edit-comp.vue文件的72行有简单注释 
  -->
  <!-- 表单 -->
  <el-form ref="baseForm"
           :class="labelPosition==='top'?'top-label':''"
           :model="formData"
           :inline="inline"
           :label-width="labelWidth"
           :size="size"
           :disabled="disabled"
           :label-position="labelPosition">
    <!-- 行内排列 -->
    <template v-if="inline">
      <!-- 表单项 -->
      <template v-for="(formItem, index) in iFormList">
        <el-form-item :key="index"
                      :label-width="formItem.labelWidth"
                      :prop="formItem.key"
                      :rules="formItem.rules"
                      v-if="formItem.vshow">
          <!-- 标题 -->
          <template v-slot:label>
            {{ formItem.label }}
          </template>
          <!-- 插槽 -->
          <template v-if="formItem.tag === 'slot'">
            <slot :name="formItem.key"
                  :formData="formData">
              {{
                formItem.filter
                  ? formItem.filter(formData)
                  : formData[formItem.key]
              }}
            </slot>
          </template>
          <!-- 单选组件 -->
          <el-radio-group v-else-if="formItem.tag === 'el-radio-group'"
                          v-model="formData[formItem.key]"
                          v-bind="formItem.props"
                          v-on="formItem.on">
            <el-radio v-for="opt in formItem.options"
                      :key="opt[(formItem.optionProps && formItem.optionProps.id) || 'id']"
                      :label="opt[(formItem.optionProps && formItem.optionProps.id) || 'id']">
              {{opt[(formItem.optionProps && formItem.optionProps.name) || "name"]}}
            </el-radio>
          </el-radio-group>
          <!-- 其它表单组件 -->
          <component v-else
                     :is="formItem.tag"
                     v-model="formData[formItem.key]"
                     v-bind="formItem.props"
                     v-on="formItem.on">
            <template v-if="formItem.tag === 'el-checkbox-group'">
              <el-checkbox v-for="opt in formItem.options"
                           :key="opt[(formItem.optionProps && formItem.optionProps.id) || 'id']"
                           :label="opt[(formItem.optionProps && formItem.optionProps.id) || 'id']">
                {{opt[(formItem.optionProps && formItem.optionProps.name) || "name"]}}
              </el-checkbox>
            </template>
            <template v-if="formItem.tag === 'el-select'">
              <el-option v-for="opt in formItem.options"
                         :key="opt[(formItem.optionProps && formItem.optionProps.id) || 'id']"
                         :label="opt[(formItem.optionProps && formItem.optionProps.name) || 'name']"
                         :value="opt[(formItem.optionProps && formItem.optionProps.id) || 'id']">
              </el-option>
            </template>
          </component>
          <!-- 表单项提示框 -->
          <el-popover v-if="formItem.tips"
                      class="tips-pop"
                      placement="top-start"
                      title="提示"
                      width="320"
                      trigger="hover"
                      :content="formItem.tips">
            <i class="el-icon-question tips-icon"
               slot="reference"></i>
          </el-popover>
        </el-form-item>
      </template>
    </template>
    <!-- 栅格排列 -->
    <el-row :gutter="20"
            v-else>
      <template v-for="(formItem, index) in iFormList">
        <el-col :key="index"
                :span="formItem.span"
                v-if="formItem.vshow">
          <template v-if="formItem.tag === 'title'">
            <el-divider v-bind="formItem.props">
              <span v-html="formItem.label"></span>
            </el-divider>
          </template>
          <!-- 表单项 -->
          <el-form-item v-else
                        :label-width="formItem.labelWidth"
                        :prop="formItem.key"
                        :rules="formItem.rules">
            <!-- 标题 -->
            <template v-slot:label>
              {{ formItem.label }}
            </template>
            <!-- 插槽 -->
            <template v-if="formItem.tag === 'slot'">
              <slot :name="formItem.key"
                    :formData="formData">
                {{
                  formItem.filter
                    ? formItem.filter(formData)
                    : formData[formItem.key]
                }}
              </slot>
            </template>
            <!-- 单选组件 -->
            <el-radio-group v-else-if="formItem.tag === 'el-radio-group'"
                            v-model="formData[formItem.key]"
                            v-bind="formItem.props"
                            v-on="formItem.on">
              <el-radio v-for="opt in formItem.options"
                        :key="opt[(formItem.optionProps && formItem.optionProps.id) || 'id']"
                        :label="opt[(formItem.optionProps && formItem.optionProps.id) || 'id']">
                {{opt[(formItem.optionProps && formItem.optionProps.name) || "name"]}}
              </el-radio>
            </el-radio-group>
            <!-- 其它表单组件 -->
            <component v-else
                       :is="formItem.tag"
                       v-model="formData[formItem.key]"
                       v-bind="formItem.props"
                       v-on="formItem.on">
              <template v-if="formItem.tag === 'el-checkbox-group'">
                <el-checkbox v-for="opt in formItem.options"
                             :key="opt[(formItem.optionProps && formItem.optionProps.id) || 'id']"
                             :label="opt[(formItem.optionProps && formItem.optionProps.id) || 'id']">
                  {{ opt[(formItem.optionProps && formItem.optionProps.name) || "name"]}}
                </el-checkbox>
              </template>
              <template v-if="formItem.tag === 'el-select'">
                <el-option v-for="opt in formItem.options"
                           :key="opt[(formItem.optionProps && formItem.optionProps.id) || 'id']"
                           :label="opt[(formItem.optionProps && formItem.optionProps.name) || 'name']"
                           :value="opt[(formItem.optionProps && formItem.optionProps.id) || 'id']">
                </el-option>
              </template>
            </component>
            <!-- 表单项提示框 -->
            <el-popover v-if="formItem.tips"
                        class="tips-pop"
                        placement="top-start"
                        title="提示"
                        width="320"
                        trigger="hover"
                        :content="formItem.tips">
              <i class="el-icon-question tips-icon"
                 slot="reference"></i>
            </el-popover>
          </el-form-item>
        </el-col>
      </template>
    </el-row>
  </el-form>
</template>

<script>
export default {
  name: "BaseForm",
  props: {
    // 表单配置
    formList: {
      type: Array,
      default: () => [],
    },
    // 表单数据
    formData: {
      type: Object,
      default: () => ({}),
    },
    // 行内展示
    inline: {
      type: Boolean,
      default: false,
    },
    // 标题宽度
    labelWidth: {
      type: String,
      default: "auto",
    },
    // 表单大小
    size: {
      type: String,
      default: "small",
    },
    // 禁用
    disabled: {
      type: Boolean,
      default: false,
    },
    // 标签的位置
    labelPosition: {
      type: String,
      default: "right",
    }
  },
  data() {
    return {
      // 表单配置
      iFormList: [],
      // 接口获取所有选项数据
      options: {},
    };
  },
  mounted() {
    this.getOptions();
    this.initFormList();
    this.$watch("formList", this.initFormList, { deep: true });
    this.$watch("formData", this.initFormList, { deep: true });
    this.$watch("options", this.initFormList, { deep: true });
  },
  methods: {
    // 接口获取数据字典选项
    getOptions() {
      this.formList.forEach((item) => {
        if (item.options && typeof item.options === "function") {
          this.$set(this.options, item.key, []);
          item.options().then((res) => {
            if (res.data) {
              this.options[item.key] = res.data;
            }
          }).catch((err) => {
            console.log(err)
          });
        }
      });
    },
    // 初始化iFormList
    initFormList() {
      const { formList, formData, deepClone, options } = this;
      this.iFormList = formList.map((item, index) => {
        const newItem = deepClone(item);
        if (item.key && !(item.key in formData)) {
          if ("default" in item) {
            this.$set(formData, item.key, item.default);
          } else if (!["slot", "title"].includes(item.tag)) {
            this.$set(formData, item.key, "");
          }
        }
        newItem.vshow = true;
        if (item.vshow === false) {
          newItem.vshow = false;
        }
        if (item.options && typeof item.options === "function") {
          delete newItem.options;
          if (options[item.key]) {
            newItem.options = [...options[item.key]]
          }
        }
        if (item.on) {
          for (let key in item.on) {
            const fn = item.on[key];
            newItem.on[key] = (event) => fn(event, formData, options);
          }
        }

        return newItem;
      });
    },
    // 深拷贝函数
    deepClone(obj) {
      if (typeof obj === "string") {
        return obj;
      }
      if (typeof obj === "number") {
        return obj;
      }
      if (typeof obj === "boolean") {
        return obj;
      }
      if (typeof obj === "undefined") {
        return obj;
      }
      if (typeof obj === "function") {
        return obj;
      }
      if (obj === null) {
        return obj;
      }
      if (Array.isArray(obj)) {
        const newObj = [];
        obj.forEach((item) => {
          newObj.push(this.deepClone(item));
        });
        return newObj;
      }
      const newObj = {};
      for (let key in obj) {
        newObj[key] = this.deepClone(obj[key]);
      }
      return newObj;
    },
    // 提交验证
    submit() {
      const result = {
        validate: false,
        data: {},
      };
      this.$refs.baseForm.validate((bool) => {
        if (bool) {
          result.validate = true;
          result.data = this.deepClone(this.formData);
        }
      });

      return result;
    },
    resetForm() {
      this.$refs.baseForm.resetFields()
    }
  },
};
</script>

<style lang="less" scoped>
.el-form-item {
  position: relative;
  /deep/.el-form-item__label {
    line-height: unset;
    height: 32px;
    display: flex;
    justify-content: flex-end;
    align-items: center;
    float: left;
  }
  .tips-pop {
    position: absolute;
    left: -12px;
    top: -10px;
    z-index: 10;
    .tips-icon {
      font-size: 16px;
    }
  }
}

.top-label {
  .el-form-item {
    /deep/.el-form-item__label {
      float: unset;
      justify-content: start;
    }
    .tips-pop {
      left: -2px;
      top: -18px;
    }
  }
}
.el-select{
  width: 100%;
}
</style>
